import subprocess
import os
from ssr.config.ssr_config import SSRConfig


class MultiScaleReconstructor:

    # https://lmb.informatik.uni-freiburg.de/people/ummenhof/multiscalefusion/
    # README:
    # < pointfusion_octree>
    #       This program takes a point cloud with normal and scale information
    #        as input and generates a compressed octree representation.
    #       The point cloud must be stored in PLY format.
    # < pointfusion_surface >
    #       This program takes the octree generated by pointfusion_octree and
    #       computes the surface mesh.

    def __init__(self):

        self.NAME_OCTREE_FILE = "octree"

        self.ssr_config = SSRConfig.get_instance()
        self.gdmr_bin_dp = self.ssr_config.get_option_value("gdmr_bin_dp", str)
        self.octree_executable_fp = os.path.join(
            self.gdmr_bin_dp, "pointfusion_octree"
        )
        assert os.path.isfile(self.octree_executable_fp)

        self.surface_executable_fp = os.path.join(
            self.gdmr_bin_dp, "pointfusion_surface"
        )
        assert os.path.isfile(self.surface_executable_fp)

    def create_mesh_from_point_cloud(
        self,
        point_cloud_ifp,
        workspace,
        mesh_ofp,
        density_threshold=3,
        filter_radius=3,
        lambda1=1,
        lambda2=1,
    ):
        # The default values are consistent to the values defined by the
        # pointfusion executable

        # pointfusion_octree -o octree pointcloud.ply
        octree_fp = os.path.join(workspace, self.NAME_OCTREE_FILE)
        octree_options = ["--density-threshold=" + str(density_threshold)]
        octree_options += ["--filter-radius=" + str(filter_radius)]

        subprocess.call(
            [self.octree_executable_fp, "-o", octree_fp]
            + octree_options
            + [point_cloud_ifp]
        )

        # pointfusion_surface -o mesh.ply octree
        surface_options = ["--lambda1=" + str(lambda1)]
        surface_options += ["--lambda2=" + str(lambda2)]
        subprocess.call(
            [self.surface_executable_fp, "-o", mesh_ofp]
            + surface_options
            + [octree_fp]
        )
